package com.jx.mlxg.utils.play;


import cn.hutool.json.JSONUtil;
import com.github.binarywang.wxpay.config.WxPayConfig;
import com.jx.mlxg.entity.Orders;
import com.wechat.pay.java.core.Config;
import com.wechat.pay.java.core.RSAAutoCertificateConfig;
import com.wechat.pay.java.core.RSAPublicKeyConfig;
import com.wechat.pay.java.core.exception.ServiceException;
import com.wechat.pay.java.core.notification.NotificationConfig;
import com.wechat.pay.java.core.notification.RSACombinedNotificationConfig;
import com.wechat.pay.java.service.partnerpayments.nativepay.NativePayService;
import com.wechat.pay.java.service.payments.jsapi.JsapiServiceExtension;
import com.wechat.pay.java.service.payments.jsapi.model.*;
import com.wechat.pay.java.service.payments.model.Transaction;
import com.wechat.pay.java.service.refund.RefundService;
import com.wechat.pay.java.service.refund.model.Refund;
import com.wechat.pay.java.service.refund.model.CreateRequest;
import com.wechat.pay.java.service.refund.model.QueryByOutRefundNoRequest;
import com.wechat.pay.java.service.refund.model.AmountReq;
import jakarta.annotation.Resource;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import java.io.File;
import java.math.BigDecimal;


public class WxPlay {

/**
 *     mchid：1725596634
 * appid：wx3af54edceb6bf033
 * APIV3公钥ID：PUB_KEY_ID_0117255966342025082200382285001202
 * 公钥文本地址↓
 * 商户APIv2密钥、APIV3密钥：mlxgmlxgmlxgmlxgmlxgmlxgmlxg8888
 * 微信支付操作密码：175015
 */


/**
     * 支付回调地址  todo !!!!!
     */
 private static String notifyUrl="http://47.94.21.50:3000/wxApi/notice";
    
    /**
     * 退款回调地址
     */
 public static final String REFUND_NOTIFY_URL = "http://47.94.21.50:3000/wxApi/refundNotice";

    /**
     * 商户号
     */
    public static String merchantId = "1725596634";
    /**
     * 商户API私钥路径
     */

    public static String privateKeyPath = System.getProperty("user.dir") + File.separator + "play" + File.separator + "apiclient_key.pem";
    /**
     * piclient_key.pem
     * 商户证书序列号shao
     */
    public static String merchantSerialNumber = "1990BA8B5E437B3F4B85810B6B2ABC3C773267FF";
    /**
     * 商户APIV3密钥
     */
    public static String apiV3key = "mlxgmlxgmlxgmlxgmlxgmlxgmlxg8888";

    private static  String publicKeyId="PUB_KEY_ID_0117255966342025082200382285001202";
//PUB_KEY_ID_0117101436262025031200298900002295
    private static  String publicKeyPath=System.getProperty("user.dir") + File.separator + "play" + File.separator + "pub_key.pem";

    /**
     * wx.requestPayment({ // 这一步是调起微信支付
     * "appId": res1.appId,
     * "timeStamp": res1.timeStamp,
     * "nonceStr": res1.nonceStr,
     * "package": res1.package,
     * "signType": res1.signType,
     * "paySign": res1.paySign,
     */
    // 使用自动更新平台证书的RSA配置
    // 一个商户号只能初始化一个配置，否则会因为重复的下载任务报错 //RSACombinedNotificationConfig
    public  static Config config =  new RSAPublicKeyConfig.Builder()
            .merchantId(merchantId)
            .privateKeyFromPath(privateKeyPath)
            .publicKeyFromPath(publicKeyPath)
            .publicKeyId(publicKeyId)
            .merchantSerialNumber(merchantSerialNumber)
            .apiV3Key(apiV3key)
            .build();


//    public  static   NotificationConfig notificationConfig = new RSACombinedNotificationConfig.Builder()
//            .merchantId(merchantId)
//            .privateKeyFromPath(privateKeyPath)
//            .merchantSerialNumber(merchantSerialNumber)
//            .publicKeyFromPath(publicKeyPath)
//            .publicKeyId(publicKeyId)
//            .apiV3Key(apiV3key)
//            .build();


    /**
     *  构建微信小程序支付参数
     * @param order
     * @return
     */
/*
    public static PrepayWithRequestPaymentResponse play(Orders order) {

        // 构建service
        JsapiServiceExtension service = new JsapiServiceExtension.Builder().config(config).build();
        // request.setXxx(val)设置所需参数，具体参数可见Request定义
        PrepayRequest request = new PrepayRequest();
        Amount amount = new Amount();
        amount.setTotal(new BigDecimal(100).divide(BigDecimal.valueOf(order.getTotalAmount()),BigDecimal.ROUND_DOWN).intValue());
        request.setAmount(amount);
        request.setAppid("wx3af54edceb6bf033");
        request.setMchid(merchantId);
        request.setDescription("小程序下单");
        //支付成功回调地址  你要写服务器上后端的路径 并且是ssl
        request.setNotifyUrl(notifyUrl);
        request.setOutTradeNo(order.getOrderId());
        Payer payer = new Payer();
        //微信小程序用户的openid  必填
        payer.setOpenid(order.getOpenid());
        request.setPayer(payer);

        // 调用下单方法，得到应答

        // response包含了调起支付所需的所有参数，可直接用于前端调起支付
        PrepayWithRequestPaymentResponse response = service.prepayWithRequestPayment(request);
        // 使用微信扫描 code_url 对应的二维码，即可体验Native支付

        return response;
    }
*/
    public static PrepayWithRequestPaymentResponse play(Orders order) {
        // 构建 service
        JsapiServiceExtension service = new JsapiServiceExtension.Builder().config(config).build();
        // request.setXxx(val) 设置所需参数，具体参数可见 Request 定义
        PrepayRequest request = new PrepayRequest();
        Amount amount = new Amount();

        // 检查订单总金额是否合法
        if (order.getRealAmount() == null || order.getRealAmount().compareTo(BigDecimal.ZERO) <= 0) {
            throw new IllegalArgumentException("订单总金额不合法");
        }

        // 将订单总金额转换为分，微信支付的金额单位为分
        amount.setTotal(order.getRealAmount().multiply(new BigDecimal(100)).setScale(0, BigDecimal.ROUND_DOWN).intValue());
        request.setAmount(amount);
        request.setAppid("wx3af54edceb6bf033");
        request.setMchid(merchantId);
        request.setDescription("小程序下单");
        // 支付成功回调地址 你要写服务器上后端的路径 并且是 ssl
        request.setNotifyUrl(notifyUrl);
        request.setOutTradeNo(order.getOrderId());
        Payer payer = new Payer();
        // 微信小程序用户的 openid 必填
        if (order.getOpenid() == null || order.getOpenid().isEmpty()) {
            throw new IllegalArgumentException("用户 openid 不可为空");
        }
        payer.setOpenid(order.getOpenid());
        request.setPayer(payer);

        // 调用下单方法，得到应答

        // response 包含了调起支付所需的所有参数，可直接用于前端调起支付
        PrepayWithRequestPaymentResponse response = service.prepayWithRequestPayment(request);
        // 使用微信扫描 code_url 对应的二维码，即可体验 Native 支付

        return response;
    }
    /**
     *  订单查询    自己去Transaction 对象里面的 amount  里面的payerTotal 对比 payerTotal 就是实际支付金额 --这段加在哪里  你订单查询要用再那 就加那吧，订单查询是查询订单详情接口吗还是支付用到的订单查询  支付
     *  没理解到哪个接口需要这个方法，还是说现在没有这个接口呢
     *    你不是需要查询接口吗 支付的  但是ta有回调  可以用来取消订单吧
     *    回调完，前端回调用此接口进行状态查询吗  可以调  但是有回调接口  PlayWxApiController
     *    这个可以使用postman测试吗支付的接口？还是说只能在前端请求测试 可以调用apifox 测
     */
    public static  Transaction wxOrderInfo(Orders order){
        QueryOrderByOutTradeNoRequest queryRequest = new QueryOrderByOutTradeNoRequest();
        queryRequest.setMchid(merchantId);
        queryRequest.setOutTradeNo(order.getOrderId());

        try {
            JsapiServiceExtension service = new JsapiServiceExtension.Builder().config(config).build();
            Transaction transaction = service.queryOrderByOutTradeNo(queryRequest);
            System.out.println("订单查询》》订单号："+order.getOrderId()+"查询结果："+ JSONUtil.toJsonStr(transaction));

             return  transaction;
        } catch (ServiceException e) {
            // API返回失败, 例如ORDER_NOT_EXISTS
            System.out.printf("code=[%s], message=[%s]\n", e.getErrorCode(), e.getErrorMessage());
            System.out.printf("reponse body=[%s]\n", e.getResponseBody());
        }
        return null;
    }
    
    /**
     * 申请退款
     * @param order 订单信息
     * @param refundAmount 退款金额（元）
     * @param refundReason 退款原因
     * @return 退款结果
     */
    public static Refund applyRefund(Orders order, BigDecimal refundAmount, String refundReason) {
        try {
            // 构建退款请求
            CreateRequest request = new CreateRequest();
            request.setOutTradeNo(order.getOrderId());
            // 生成退款单号
            String outRefundNo = "REF" + System.currentTimeMillis();
            request.setOutRefundNo(outRefundNo);
            
            // 设置金额信息（单位：分）
            AmountReq amount = new AmountReq();
            amount.setRefund(refundAmount.multiply(new BigDecimal(100)).setScale(0, BigDecimal.ROUND_DOWN).longValue());
            amount.setTotal(order.getRealAmount().multiply(new BigDecimal(100)).setScale(0, BigDecimal.ROUND_DOWN).longValue());
            amount.setCurrency("CNY");
            request.setAmount(amount);
            
            // 设置退款原因
            request.setReason(refundReason);
            
            // 设置退款回调地址
            request.setNotifyUrl(REFUND_NOTIFY_URL);
            
            // 构建退款服务
            RefundService refundService = new RefundService.Builder().config(config).build();
            
            // 调用退款API
            Refund refund = refundService.create(request);
            System.out.println("退款申请成功》》订单号：" + order.getOrderId() + "退款单号：" + outRefundNo + "结果：" + JSONUtil.toJsonStr(refund));
            
            return refund;
        } catch (ServiceException e) {
            System.out.printf("退款申请失败》》code=[%s], message=[%s]\n", e.getErrorCode(), e.getErrorMessage());
            System.out.printf("reponse body=[%s]\n", e.getResponseBody());
            throw e;
        }
    }
    
    /**
     * 查询退款
     * @param outRefundNo 商户退款单号
     * @return 退款信息
     */
    public static Refund queryRefund(String outRefundNo) {
        try {
            // 构建查询退款请求
            QueryByOutRefundNoRequest request = new QueryByOutRefundNoRequest();
            request.setOutRefundNo(outRefundNo);
            
            // 构建退款服务
            RefundService refundService = new RefundService.Builder().config(config).build();
            
            // 调用查询退款API
            Refund refund = refundService.queryByOutRefundNo(request);
            System.out.println("退款查询成功》》退款单号：" + outRefundNo + "结果：" + JSONUtil.toJsonStr(refund));
            
            return refund;
        } catch (ServiceException e) {
            System.out.printf("退款查询失败》》code=[%s], message=[%s]\n", e.getErrorCode(), e.getErrorMessage());
            System.out.printf("reponse body=[%s]\n", e.getResponseBody());
        }
        return null;
    }


    public static void main(String[] args)
    {
        String keyPath = System.getProperty("user.dir") + File.separator + "play" + File.separator + "apiclient_key.pem";
        System.out.println("私钥路径: " + keyPath);
        System.out.println("文件是否存在: " + new File(keyPath).exists());
//        PrepayWithRequestPaymentResponse play = play("oi8y25aE93OvQe7vQo4FOkn-fpMk"); System.out.println(play);
//        // 构造 RequestParam
//        RequestParam requestParam = new RequestParam.Builder()
//                .serialNumber(merchantSerialNumber)
//                .nonce(play.getNonceStr())
//                .signature(play.getPaySign())
//                .timestamp(play.getTimeStamp())
//                .body("")
//                .build();
//
//// 如果已经初始化了 RSAAutoCertificateConfig，可直接使用
//// 没有的话，则构造一个
//
//
//// 初始化 NotificationParser
//        NotificationParser parser = new NotificationParser(config);
//
//// 以支付通知回调为例，验签、解密并转换成 Transaction
//        Transaction transaction = parser.parse(requestParam, Transaction.class);
    }
}
